#include "lcd12864.h"

// 数字字模（共阳极，8x4 点阵）
unsigned char code NUM_CHARS[] = {
    0x7F, 0x41, 0x41, 0x7F, // 0
    0x00, 0x00, 0x00, 0x7F, // 1
    0x79, 0x49, 0x49, 0x4F, // 2
    0x49, 0x49, 0x49, 0x7F, // 3
    0x0F, 0x08, 0x08, 0x7F, // 4
    0x4F, 0x49, 0x49, 0x79, // 5
    0x7F, 0x49, 0x49, 0x79, // 6
    0x01, 0x01, 0x01, 0x7F, // 7
    0x7F, 0x49, 0x49, 0x7F, // 8
    0x4F, 0x49, 0x49, 0x7F  // 9
};

// 箭头符号字模
unsigned char code LEFT_ARROW[] = {0x08, 0x1c, 0x3e, 0x7f};
unsigned char code RIGHT_ARROW[] = {0x7f, 0x3e, 0x1c, 0x08};

// "SPEED" 字符串字模（8x5 点阵）
unsigned char code SPEED_CHARS[] = {
    0x46, 0x49, 0x49, 0x31, 0x00, // S
    0x7F, 0x09, 0x09, 0x06, 0x00, // P
    0x7F, 0x49, 0x49, 0x49, 0x00, // E
    0x7F, 0x49, 0x49, 0x49, 0x00, // E
    0x7F, 0x41, 0x41, 0x3E, 0x00  // D
};

/**
 * @brief 毫秒延时函数
 * @param ms 延时毫秒数
 */
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 120; j++);  // 120 是基于 11.0592MHz 晶振的经验值
}

/**
 * @brief 向 LCD12864 写入命令
 * @param cmd 命令字节
 */
void lcd_write_cmd(unsigned char cmd) {
    LCD_RS = 0;      // 选择指令寄存器
    LCD_RW = 0;      // 写入模式
    LCD_DATA_PORT = cmd;  // 发送命令
    delay_ms(1);     // 等待稳定
    LCD_E = 1;       // 使能信号上升沿
    delay_ms(1);     // 保持时间
    LCD_E = 0;       // 使能信号下降沿触发命令执行
}

/**
 * @brief 向 LCD12864 写入数据
 * @param dat 数据字节
 */
void lcd_write_data(unsigned char dat) {
    LCD_RS = 1;      // 选择数据寄存器
    LCD_RW = 0;      // 写入模式
    LCD_DATA_PORT = dat;  // 发送数据
    delay_ms(1);     // 等待稳定
    LCD_E = 1;       // 使能信号上升沿
    delay_ms(1);     // 保持时间
    LCD_E = 0;       // 使能信号下降沿触发数据写入
}

/**
 * @brief 初始化 LCD12864
 */
void lcd_init(void) {
    lcd_write_cmd(0x30);  // 选择基本指令集
    delay_ms(5);
    lcd_write_cmd(0x0C);  // 显示开，光标关，闪烁关
    delay_ms(5);
    lcd_write_cmd(0x01);  // 清屏
    delay_ms(5);
    lcd_write_cmd(0x06);  // 文字不动，光标自动右移
    delay_ms(5);
}

/**
 * @brief 在指定位置显示自定义字符
 * @param x 列位置 (0-127)
 * @param y 行位置 (0-3)
 * @param chr 字符点阵数据指针
 */
void lcd_show_custom_char(unsigned char x, unsigned char y, unsigned char *chr) {
    // 根据行位置设置 DDRAM 地址
    switch(y) {
        case 0: lcd_write_cmd(0x80 + x); break;  // 第一行
        case 1: lcd_write_cmd(0x90 + x); break;  // 第二行
        case 2: lcd_write_cmd(0x88 + x); break;  // 第三行
        case 3: lcd_write_cmd(0x98 + x); break;  // 第四行
        default: break;
    }

    // 写入字符点阵数据
    for(unsigned char i = 0; i < 4; i++) {  // 每个字符占 4 字节高度
        lcd_write_data(chr[i]);
    }
}

/**
 * @brief 显示 "SPEED" 字符串
 */
void show_speed_string(void) {
    // 显示 "SPEED" 每个字符，字符间距 5 列
    lcd_show_custom_char(0, 1, &SPEED_CHARS[0]);   // S
    lcd_show_custom_char(5, 1, &SPEED_CHARS[5]);   // P
    lcd_show_custom_char(10, 1, &SPEED_CHARS[10]); // E
    lcd_show_custom_char(15, 1, &SPEED_CHARS[15]); // E
    lcd_show_custom_char(20, 1, &SPEED_CHARS[20]); // D
}

/**
 * @brief 显示当前速度值
 */
void show_speed_value(void) {
    // 在中间位置显示速度值（假设为 1-9）
    lcd_show_custom_char(30, 1, &NUM_CHARS[speedValue * 4]);
}

/**
 * @brief 显示左右箭头
 */
void show_arrows(void) {
    // 左箭头
    lcd_show_custom_char(5, 2, LEFT_ARROW);
    // 右箭头
    lcd_show_custom_char(45, 2, RIGHT_ARROW);
}

/**
 * @brief 显示完整的速度调节界面
 */
void show_speed_interface(void) {
    lcd_write_cmd(0x01);  // 清屏
    show_speed_string();  // 显示 "SPEED"
    show_speed_value();   // 显示当前速度值
    show_arrows();        // 显示左右箭头
}